package com.evolved.automata.experimental;

public class SequenceMaker {
	int[][] j_SequenceHistory;
	int j_ActionGroupRadius;
	int j_StateGroupRadius;
	int j_StateGroupDepth;
	int j_ActionGroupDepth;
	InitializationPolicy j_InitPolicy;
	boolean j_First;
	
	public static enum InitializationPolicy
	{
		EXTEND_FIRST_POINT, PRIOR_VALUES_UNKNOWN
	}
	public SequenceMaker(int stateGroupRadius, int stateGroupDepth, int actionGroupRadius, int actionGroupDepth, InitializationPolicy initializationPolicy)
	{
		j_SequenceHistory = new int[stateGroupRadius+actionGroupRadius][];
		j_ActionGroupRadius=actionGroupRadius;
		j_StateGroupRadius=stateGroupRadius;
		j_StateGroupDepth=stateGroupDepth;
		j_ActionGroupDepth=actionGroupDepth;
		j_InitPolicy=initializationPolicy;
		j_First=true;
		for (int i=0;i<j_StateGroupRadius+j_ActionGroupRadius;i++)
		{
			if ((0<=i)&&(i<j_StateGroupRadius))
			{
				j_SequenceHistory[i] = new int[j_StateGroupDepth];
			}
			else
			{
				j_SequenceHistory[i] = new int[j_ActionGroupDepth];
			}
			
		}
		
	}
	

	
	// TODO: Add a constructor which only takes state parameters
	
	private void ConstructInitialPoint(int[] firstStateGroup, int[] firstActionGroup)
	{
		for (int i=0;i<j_StateGroupRadius+j_ActionGroupRadius;i++)
		{
			if ((0<=i)&&(i<j_StateGroupRadius))
			{
				for (int j=0;j<j_StateGroupDepth;j++)
					j_SequenceHistory[i][j]=ArbitrateInitialValue(firstStateGroup[i],j==0);
			}
			else
			{
				for (int j=0;j<j_ActionGroupDepth;j++)
					j_SequenceHistory[i][j]=ArbitrateInitialValue(firstActionGroup[i-j_StateGroupRadius], j==0);
			}
			
		}
		
	}
	
	private int ArbitrateInitialValue(int initialValue, boolean firstP)
	{
		
		if ((j_InitPolicy==InitializationPolicy.EXTEND_FIRST_POINT)||(firstP))
			return initialValue;
		else
			return -1;
			
	}
	
	public int[] AddStateActionGroups(int[] stateGroup, int[] actionGroup)
	{
		if (j_First)
		{
			j_First=false;
			ConstructInitialPoint(stateGroup,actionGroup );
		}
		else
		{
			// Shift back all past states and actions
			for (int i=0;i<j_StateGroupRadius+j_ActionGroupRadius;i++)
			{
				if ((0<=i)&&(i<j_StateGroupRadius))
				{
					for (int j=j_StateGroupDepth-1;j>0;j--)
						j_SequenceHistory[i][j]=j_SequenceHistory[i][j-1];
					j_SequenceHistory[i][0]=stateGroup[i];
				}
				else
				{
					for (int j=j_ActionGroupDepth-1;j>0;j--)
						j_SequenceHistory[i][j]=j_SequenceHistory[i][j-1];
					j_SequenceHistory[i][0]=actionGroup[i-j_StateGroupRadius];
				}
				
			}
		}
		return Flatten();
	}
	
	private int[] Flatten()
	{
		int[] output = new int[j_StateGroupRadius*j_StateGroupDepth+j_ActionGroupRadius*j_ActionGroupDepth];
		int k=0;
		for (int i=0;i<j_StateGroupRadius+j_ActionGroupRadius;i++)
		{
			if ((0<=i)&&(i<j_StateGroupRadius))
			{
				for (int j=0;j<j_StateGroupDepth;j++)
				{
					output[k++]=j_SequenceHistory[i][j];
				}
			}
			else
			{
				for (int j=0;j<j_ActionGroupDepth;j++)
				{
					output[k++]=j_SequenceHistory[i][j];
				}
			}
		}
		return output;
	}
	
}
